package cn.wx.read.neo4j.service;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.neo4j.ogm.model.Result;
import org.springframework.beans.factory.annotation.Autowired;

import cn.wx.read.core.entity.ScholarMaxData;
import cn.wx.read.core.entity.qo.ScholarMaxDataQ;
import cn.wx.read.core.service.ScholarMaxDataService;
import cn.wx.read.neo4j.entity.Neo4jBook;
import cn.wx.read.neo4j.entity.Neo4jExpert;
import cn.wx.read.neo4j.entity.Neo4jPaper;
import cn.wx.read.neo4j.entity.Neo4jPatents;
import cn.wx.read.neo4j.repository.ComputeRepository;
import cn.wx.read.utils.N2OUtils;

/**
 * N-index , A-index , I-index,P-index,g-index
 * 
 * book数, patent专利数 , patent-cit专利引用数 , paper 论文数 
 * 
 * 参数 : h-index , citation
 * 
 * @author Administrator
 */
public class ComputeExpertService {
	
	/**
	 * 启动线程数
	 */
	private final static int THREAD_NUM = 7;
	
	/**
	 * 用于计算的最大值
	 */
	private static ScholarMaxData MAX_DATA;
	
	/**
	 * 线程池
	 */
	private ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_NUM);
	
	@Autowired
	private ComputeRepository computeRepository;
	
	@Autowired
	private ScholarMaxDataService scholarMaxDataService;
	
	/**
	 * 检索需要计算的人
	 * 开启多线程计算，按人分配
	 * 开启定时器
	 * 每一分钟 查看 线程池还有有没执行的线程
	 */
	//@Scheduled(cron="0 0/1 *  * * ? ") 
	public void scheduledCompute() {
		
		/**
		 * 线程全部执行完毕
		 * 启动新的开启下一个
		 */
		if(threadPool.isShutdown()) {
			if(threadPool.isTerminated()) {
				/**
				 * 先判断当前分片还有没有没有读取的文件
				 */
				threadPool = Executors.newFixedThreadPool(THREAD_NUM);
				loadComputeExperts();
			}
		} else {
			loadComputeExperts();
		}
		
	}
	
	
	/**
	 * 分配专家到线程
	 */
	public void loadComputeExperts(){
		
		/**
		 * 每次启动线程 ， 都要计算一次最大值
		 */
		MAX_DATA = scholarMaxDataService.queryUniqueByXML(new ScholarMaxDataQ());
		
		/**
		 * 获取带计算的专家值
		 */
		Result result = computeRepository.loadComputeExperts();
		
		/**
		 * 转化list ，便于解析
		 */
		List<Neo4jExpert> els = N2OUtils.covetResultToDTO(result, Neo4jExpert.class);
		
		if(els == null || els.size() == 0) { return; }
		
		List<List<Neo4jExpert>> les = N2OUtils.averageAssign(els, THREAD_NUM);
		
		/**
		 * 计算开启线程
		 */
		for(List<Neo4jExpert> ces : les) {
			threadPool.execute(new ThreadMultiReader(ces));
		}
	}
	
	/**
	 * 开启内部类线程
	 * @author zj
	 *
	 */
	class ThreadMultiReader implements Runnable{

		/**
		 * 需要计算的专家fId集合
		 */
		private List<Neo4jExpert> computeExperts;
		
		
		
		public ThreadMultiReader(List<Neo4jExpert> computeExperts) {
			this.computeExperts = computeExperts;
		}
		
		/**
		 *  执行线程
		 */
		@Override
		public void run() {
			threadCompute();
		}
		
		/**
		 * 计算入口
		 */
		public void threadCompute () {
			
			/**
			 * 循环计算每一个人
			 */
			for(Neo4jExpert ce : computeExperts) {
				
				if(ce == null || ce.getId() == null) { continue; }
				/**
				 * 图书
				 */
				Result rb = computeRepository.computeBook(ce.getId());
				List<Neo4jBook> rbl = N2OUtils.covetResultToDTO(rb, Neo4jBook.class);
				/**
				 * 论文
				 */
				Result rp = computeRepository.computePaper(ce.getId());
				List<Neo4jPaper> rpl = N2OUtils.covetResultToDTO(rp, Neo4jPaper.class);
				
				/**
				 * 专利
				 */
				Result rpt = computeRepository.computePatents(ce.getId());
				List<Neo4jPatents> rptl = N2OUtils.covetResultToDTO(rpt, Neo4jPatents.class);
				
				Integer hIndex = 0;//ce.gethIndex(); //hindex
				Integer citations = 0;//ce.getCitations(); //专家引用数
				
				Integer bnum = rbl.size(); //图书数
				Integer pnum = rpl.size(); //论文数
				Integer patentsNum = rptl.size(); //专利数
				
				Integer cnum = 0;	//会议数量
				Integer jnum = 0;	//期刊数量
				Integer patentsCit = 0; //专利引用数
				
				/**
				 * 循环论文处理论文的
				 */
				/*for(Neo4jPaper paper : rpl) {
					switch (paper.getDocType()) {
					case "Journal":jnum++;break;
					case "Conference":cnum++;break;
					default:
						break;
					}
				}*/
				
				/**
				 * 处理专利
				 */
				for(Neo4jPatents patent : rptl) {
					patentsCit += patent.getCit();
				}
				
				/**
				 * 调用公式 计算
				 */
				Double chIndex = conputeAindex(hIndex, pnum, citations, bnum);
				
				Double cGIndex = conputeGindex(hIndex);
				
				//Double cPIndex = conputePindex(nnum, snum);
				
				
			}
		}

		public List<Neo4jExpert> getComputeExperts() {
			return computeExperts;
		}

		public void setComputeExperts(List<Neo4jExpert> computeExperts) {
			this.computeExperts = computeExperts;
		}

	}


	/**
	 * 计算g-index
	 * 1.8*e.`h-index`
	 */
	public Double conputeGindex(Integer hIndex) {
		return 1.8*hIndex;
	}
	
	
	/**
	 * 计算a-index
	 * (log(hindex+1.0)/log(maxhindex))*0.25+(log(pnum+1.0)/log(maxpnum))*0.35
	 *  +(log(citations+1.0)/log(maxcitations))*0.1+(log(bnum+1.0)/log(maxbnum)*0.3)
	 */
	public Double conputeAindex(Integer hIndex,Integer pnum,Integer citations,Integer bnum) {
		Double log_hIndex = Math.log(hIndex + 1.0)/Math.log(MAX_DATA.gethIndex());
		Double log_pnum = Math.log(pnum + 1.0)/Math.log(MAX_DATA.getPnum());
		Double log_citations = Math.log(citations + 1.0)/Math.log(MAX_DATA.getCitations());
		Double log_bnum = Math.log(bnum + 1.0)/Math.log(MAX_DATA.getBnum());
		return (log_hIndex * 0.25 + log_pnum * 0.35 + log_citations * 0.1 + log_bnum * 0.3) * 100;
	}
	
	/**
	 * 计算n-index
	 * 0.7*e.AIndex*100+0.1*e.iIndex+0.2*e.pIndex
	 */
	public void conputeNindex() {
		
	}

	/**
	 * 计算i-index
	 */
	public void conputeIindex() {
		
	}
	
	/**
	 * 计算p-index
	 * ((log(nnum+1.0)/log(maxnnum)*0.6+log(snum+1.0)/log(maxsnum)*0.4)*100)
	 */
	public Double conputePindex(Integer nnum,Integer snum) {
		
		Double log_nnum = Math.log(nnum + 1.0)/Math.log(MAX_DATA.getNnum());
		
		Double log_snum = Math.log(snum + 1.0)/Math.log(MAX_DATA.getSnum());
		
		return (log_nnum*0.6 + log_snum*0.4) * 100;
	}
	
}
